/**************************************************************
    My Database Connection Pool
***************************************************************/
package linuxbox.util;

import java.util.*;
import linuxbox.BoxStatic;

public abstract class ObjectPool {
    protected boolean m_bInited;  
    protected int m_nInitSize;
    protected int m_nMaxSize;
    protected long m_lETime;
    
    protected List pool = new ArrayList();
    protected int usageCount = 0;
    //private CleanUpThread cleaner;

    /**
      Below 3 function must be defined in the child class 
        objCreate   Create it!
        objValidate give me if it is valid
        objExpire   notify child class that this object is expired
    */
    abstract Object objCreate() throws Exception;
    abstract boolean objValidate(Object obj);
    abstract void objExpire(Object obj);

    protected ObjectPool() {
        m_nInitSize = BoxStatic.initSize;
        m_nMaxSize  = BoxStatic.maxSize;
        m_lETime    = BoxStatic.expireTime;
        m_bInited   = false;
        //cleaner = new CleanUpThread( this, m_lETime );
        //cleaner.start();
    }

    protected ObjectPool(long etime) {
        m_nInitSize = BoxStatic.initSize;
        m_nMaxSize  = BoxStatic.maxSize;
        m_lETime    = etime;
        m_bInited   = false;
    }

    protected ObjectPool(long etime, int isize) {
        m_nInitSize = isize;
        m_nMaxSize  = BoxStatic.maxSize;
        m_lETime    = etime;
        m_bInited   = false;
    }

    protected ObjectPool(long etime, int isize, int msize) {
        m_nInitSize = isize;
        m_nMaxSize  = msize;
        m_lETime    = etime;
        m_bInited   = false;
    }

    protected void initOP() throws Exception {
        for (int i = 0; i < m_nInitSize; i++) {
            ObjectWrapper ow = ObjectWrapper.getInstance(
                objCreate(), calcExpireTime());
            pool.add(ow);
        }
        m_bInited = true;
    }

    protected long calcExpireTime() {
        long ret = 0;
        if (m_lETime == -1) {
            ret = -1;
        } else {
            ret = System.currentTimeMillis() + m_lETime;
        }
        return ret;
    }
    
    public synchronized Object checkOut() throws Exception {
        Object ret = null;
        long now = System.currentTimeMillis();

        if (!m_bInited) initOP();

        if (!pool.isEmpty()) {
            for (Iterator it = pool.iterator(); it.hasNext(); ) {
                ObjectWrapper ow = (ObjectWrapper)it.next();
                if (ow.checkExpire(now)) {
                    it.remove();
                    objExpire(ow.getObject());
                } else {
                    it.remove();
                    Object tmp = ow.getObject();
                    if (objValidate(tmp)) {
                        usageCount++;
                        ret = tmp;
                        break;
                    } else {
                        objExpire(tmp);
                    }
                }
            }
        } else if (m_nMaxSize > (pool.size() + usageCount)) {
            ret = objCreate();
            usageCount++;
        } else {
            throw new Exception("Exceed pool size" + m_nMaxSize);
        }
        
        return ret;
    }   
    
    public synchronized void checkIn(Object o) { 
        usageCount--; 
        if (objValidate(o)) {
            pool.add(ObjectWrapper.getInstance(o, calcExpireTime()));
        }
    } 
    
    public synchronized void cleanUp() {
        long now = System.currentTimeMillis();
            
        for (Iterator it = pool.iterator(); it.hasNext(); ) {
            ObjectWrapper ow = (ObjectWrapper)it.next();
    
            if (ow.checkExpire(now)) {
                it.remove();
                objExpire(ow.getObject());
            }
        }
            
        //System.gc();
    }

    public synchronized void cleanAll() {
        for (Iterator it = pool.iterator(); it.hasNext(); ) {
            ObjectWrapper ow = (ObjectWrapper)it.next();
    
            it.remove();
            objExpire(ow.getObject());
        }
    }
}

